/*
 * @Author: zi.yang
 * @Date: 2022-02-08 08:04:41
 * @LastEditors: zi.yang
 * @LastEditTime: 2022-02-11 23:51:26
 * @Description: message 消息容器
 * @FilePath: \api-generator\app\public\js\message.js
 */
'use strict';

/**
 * 获取消息类型
 * @param { String } type 消息状态类型
 * @return { Object } 消息状态及图标
 */
function messageType(type) {
  switch (type) {
    case 'success':
      return { class: 'alert-success', icon: 'fa-check-circle' };
    case 'error':
      return { class: 'alert-danger', icon: 'fa-times-circle' };
    case 'info':
      return { class: 'alert-info', icon: 'fa-info-circle' };
    case 'warning':
      return { class: 'alert-warning', icon: 'fa-exclamation-triangle' };
    case 'loading':
      return { class: 'alert-primary', icon: 'fa-spinner fa-spin' };
    default:
      return { class: 'alert-secondary', icon: '' };
  }
}
/**
 * 生成消息唯一ID
 * @return { String } ID
 */
function createMsgId() {
  const num = Math.random().toString(26).substr(2);
  const id = (Math.random() * 100000).toFixed(0);
  return num + id;
}

/**
 * 刷新当前消息列表布局
 */
function refresh_msgList() {
  $.each($('.zy-message--hook'), (idx, ele) => {
    const top = idx === 0 ? '20px' : (idx * 80 + 20) + 'px';
    $(ele).css({ transform: 'translate(-50%,' + top + ')' });
  });
}

/**
 * 消息移出 - 定时器
 * @param { Document } dom rq
 * @param { Number } time 定时移出消息
 * @param { Number } count 当前消息数量
 */
function messageRemoveTimer(dom, time, count = 0) {
  // 定时关闭消息
  const _count = count !== 0 ? count : this._msgCount;
  const msgId = $(dom).attr('data-msg-id');
  const timer = setTimeout(() => {
    // 移除定时器缓存
    const idx = this._timerList.findIndex(t => t.msgId === msgId);
    this._timerList.splice(idx, 1);
    // 移除消息
    $(dom).fadeOut(500);
    const innerTimer = setTimeout(() => {
      $(dom).remove();
      refresh_msgList();
      removeMsgListCache.call(this, dom);
      clearTimeout(innerTimer);
    }, 500);
    // 清除消息定时器
    clearTimeout(timer);
  }, time * _count);
  // 添加定时器缓存
  this._timerList.push({ msgId, timer });
}

/**
 * 刷新消息定时器：刷新当前所有消息的定时
 */
function resetMessageTimer() {
  this._timerList.forEach((timer, idx) => {
    if (idx === 0) return;
    clearTimeout(timer.timer);
  });
  this._timerList.splice(1);
  $.each($('.zy-message--hook'), (idx, ele) => {
    if (idx === 0) return;
    const msgId = $(ele).attr('data-msg-id');
    const msgCache = this._msgList.find(item => item.id === msgId);
    messageRemoveTimer.call(this, ele, msgCache.time, idx);
  });
}

/**
 * 移除缓存列表中的消息
 * @param { Element } msgDom 消息容器
 */
function removeMsgListCache(msgDom) {
  this._msgCount -= 1;
  const msgId = $(msgDom).attr('data-msg-id');
  const msgIndex = this._msgList.findIndex(item => item.id === msgId);
  this._msgList.splice(msgIndex, 1);
}

/**
 * 关闭消息事件
 * @param { Element } dom 消息容器
 * @param { Function } messageRemoveCallback 事件回调
 */
function closeMessageEvent(dom, messageRemoveCallback) {
  const messageDom = $(dom).find('.alert').get(0);
  const self = this;
  // 添加事件：不要使用 Bootstrap 封装的 closed.bs.alert 事件，会产生BUG
  $(messageDom).find('[aria-label="Close"]').on('click', function() {
    const msgDom = $(this).parent().parent();
    msgDom.fadeOut(500);
    const timer = setTimeout(() => {
      msgDom.remove();
      refresh_msgList();
      removeMsgListCache.call(self, msgDom);
      resetMessageTimer.call(self);
      messageRemoveCallback();
      clearTimeout(timer);
    }, 500);
  });
}

/**
 * 创建消息 DOM
 * @param { String } msgId 消息ID
 * @param { String } text 消息文本
 * @param { String } type 消息类型
 * @return { Element } 消息容器DOM
 */
function baseMessageHtml(msgId, text, type) {
  const { class: classStyle, icon } = messageType(type);
  // 消息html结构
  const html = `
    <div class="alert alert-primary alert-dismissible" role="alert">
      <i class="bi flex-shrink-0 me-2 fs-medium fas"></i>
      <p class="zy-message-text--hook fs-medium" style="display:inline-block">${text}</p>
      <button type="button" class="close" aria-label="Close">&times;</button>
    </div>
  `;
  // 消息容器样式
  const boxStyle = {
    position: 'absolute',
    top: '0',
    left: '50%',
    transform: 'translate(-50%,20px)',
    zIndex: '10000',
    transition: 'transform .5s linear',
    display: 'none',
  };

  // 处理容器及消息组件
  const dom = document.createElement('div');
  $(dom).addClass('zy-message--hook').css(boxStyle)
    .append(html)
    .attr({ 'data-msg-id': msgId });
  $(dom).find('.alert').addClass(classStyle)
    .css({ height: '60px' });
  $(dom).find('.alert > i').addClass(icon);
  return dom;
}

/**
 * 在页面生成消息
 * @param { Element } dom 消息容器DOM
 */
function appendMessageBox(dom) {
  const { _msgCount } = this;

  if (_msgCount !== 0) {
    const top = (_msgCount * 80 + 20) + 'px';
    $(dom).css({ transform: 'translate(-50%,' + top + ')' });
  }
  this._msgCount += 1;
  $(document.body).append(dom);
  $('.zy-message--hook').slideDown(300);
}

const msgType = [ 'success', 'error', 'info', 'warning', 'loading' ];
const message = {};
const messageX = {};

// 添加消息组件
msgType.forEach(type => {
  /**
   * 消息组件
   * @param { String } msg 消息文本
   * @param { Number } time 显示时长（毫秒），默认3秒
   * @param { Function } messageRemoveCallback 消息移出后的回调
   */
  message[type] = function(msg = '', time = 3000, messageRemoveCallback = () => {}) {
    const msgId = createMsgId();
    this._msgList.push({ id: msgId, msg, type, time });
    const dom = baseMessageHtml.call(this, msgId, msg, type);
    appendMessageBox.call(this, dom);
    closeMessageEvent.call(this, dom, messageRemoveCallback);
    messageRemoveTimer.call(this, dom, time);
  };
  /**
   * 消息组件-增强组件：自动拦截重复消息
   * @param { String } msg 消息文本
   * @param { Number } time 显示时长（毫秒），默认3秒
   * @param { Function } messageRemoveCallback 消息移出后的回调
   */
  messageX[type] = function(msg = '', time = 3000, messageRemoveCallback = () => {}) {
    const messageExists = this._msgList.find(item => item.msg === msg && item.type === type);
    if (messageExists) return;
    $.message[type](msg, time, messageRemoveCallback);
    // const msgId = createMsgId();
    // this._msgList.push({ id: msgId, msg, type, time });
    // const dom = baseMessageHtml.call(this, msgId, msg, type);
    // appendMessageBox.call(this, dom);
    // closeMessageEvent.call(this, dom, messageRemoveCallback);
    // messageRemoveTimer.call(this, time);
  };
});

// 添加到 Jquery 实例
$.extend({
  // 全局消息组件
  message: {
    // 消息数量
    _msgCount: 0,
    // 消息列表
    _msgList: [],
    _timerList: [],
    // 消息方法
    ...message,
    // alias warning
    warn(msg, time, messageRemoveCallback) {
      this.warning(msg, time, messageRemoveCallback);
    },
  },
  // 全局消息增强组件：拦截重复消息
  messageX: {
    // 消息数量
    _msgCount: 0,
    // 消息列表
    _msgList: [],
    // 消息方法
    ...messageX,
    // alias warning
    warn(msg, time, messageRemoveCallback) {
      this.warning(msg, time, messageRemoveCallback);
    },
  },
});
